﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Phone.Tasks;
using System.IO;
using System.Collections.Generic;
using System.Linq;

namespace Tsina
{
    public class OAuthHelper
    {
        public static string appKey = "3076956568";
        public static string appSecret = "052c686ea52ccb14bac7d147264bbf40";
        public static string requestTokenUrl;
        public static string authorizeUrl;
        public static string accessTokenUrl;

        public static string requestToken;
        public static string requestTokenSecret;
        public static string accessToken = "88211a5b79af68d5295e9ff7fcc6bce3";
        public static string accessTokenSecret = "33581f6b9071e57bc2ac01ab5e4de484";
        public static string userId = "1401230242";

        private enum HttpVerb
        {
            GET,
            POST
        }

        private enum ProtocolParameters
        {
            oauth_consumer_key,
            oauth_token,
            oauth_signature_method,
            oauth_timestamp,
            oauth_nonce,
            oauth_signature,
            oauth_verifier,
            oauth_token_secret,
            oauth_callback
        }

        private static string SignatureBaseString(HttpVerb verb, string requestUrl, Dictionary<ProtocolParameters, string> protocolParameters, Dictionary<string, string> postedData, string appSecret, string oauthTokenSecret)
        {
            List<string> list = new List<string>();
            foreach (var parameter in protocolParameters)
            {
                list.Add(OAuthUrlEncode(parameter.Key.ToString()) + "=" + OAuthUrlEncode(parameter.Value));
            }

            if (verb == HttpVerb.POST && postedData != null && postedData.Count > 0)
            {
                foreach (var parameter in postedData)
                {
                    list.Add(OAuthUrlEncode(parameter.Key) + "=" + OAuthUrlEncode(parameter.Value));
                }
            }

            var sortedParameters = list.OrderBy(x => x);

            StringBuilder parametersBuilder = new StringBuilder();
            foreach (var parameter in sortedParameters)
            {
                parametersBuilder.Append(parameter);
                parametersBuilder.Append("&");
            }
            string parametersString = parametersBuilder.ToString().TrimEnd('&');
            
            string baseString = verb.ToString() + "&" + OAuthUrlEncode(requestUrl) + "&" + OAuthUrlEncode(parametersString);

            HMACSHA1 sha1 = new HMACSHA1();
            sha1.Key = Encoding.UTF8.GetBytes(appSecret + "&" + oauthTokenSecret);
            byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(baseString));
            string signature = Convert.ToBase64String(hash);

            return signature;
        }

        private static string GetAuthorizationString(Dictionary<ProtocolParameters, string> protocolParameters)
        {
            StringBuilder authorizationBuilder = new StringBuilder();
            authorizationBuilder.Append("OAuth realm=\"Example\",");
            foreach (var parameter in protocolParameters)
            {
                authorizationBuilder.Append(parameter.Key.ToString());
                authorizationBuilder.Append("=\"");
                authorizationBuilder.Append(OAuthUrlEncode(parameter.Value));
                authorizationBuilder.Append("\",");
            }

            return authorizationBuilder.ToString().TrimEnd(',');
        }

        public static void OpenAuthorizeUrl()
        {
            XDocument config = XDocument.Load("Config.xml");
            appKey = config.Root.Element("AppKey").Value;
            appSecret = config.Root.Element("AppSecret").Value;
            requestTokenUrl = config.Root.Element("RequestTokenURL").Value;
            authorizeUrl = config.Root.Element("AuthorizeURL").Value;
            accessTokenUrl = config.Root.Element("AccessTokenURL").Value;

            string timeSpan = GetTimeSpan();

            Dictionary<ProtocolParameters, string> protocolParameters = new Dictionary<ProtocolParameters, string>();
            protocolParameters.Add(ProtocolParameters.oauth_consumer_key, appKey);
            protocolParameters.Add(ProtocolParameters.oauth_nonce, timeSpan);
            protocolParameters.Add(ProtocolParameters.oauth_signature_method, "HMAC-SHA1");
            protocolParameters.Add(ProtocolParameters.oauth_timestamp, timeSpan);

            string signature = SignatureBaseString(HttpVerb.GET, requestTokenUrl, protocolParameters, null, appSecret, null);

            protocolParameters.Add(ProtocolParameters.oauth_signature, signature);
            string authorizationString = GetAuthorizationString(protocolParameters);

            WebClient client = new WebClient();
            client.Headers["Authorization"] = authorizationString;
            client.OpenReadCompleted += new OpenReadCompletedEventHandler(CompleteRequestToken);
            client.OpenReadAsync(new Uri(requestTokenUrl));
        }

        private static void CompleteRequestToken(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                Stream reply = null;
                StreamReader reader = null;
                string content = string.Empty;

                try
                {
                    reply = (Stream)e.Result;
                    reader = new StreamReader(reply);
                    content = reader.ReadLine();
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }

                    if (reply != null)
                    {
                        reply.Close();
                    }
                }

                string[] tokens = content.Split('&');

                if (tokens.Length != 2)
                {
                    return;
                }

                Dictionary<string, string> dict = new Dictionary<string, string>();

                foreach (string item in tokens)
                {
                    string[] keyValue = item.Split('=');
                    dict.Add(keyValue[0], keyValue[1]);
                }

                requestToken = dict[ProtocolParameters.oauth_token.ToString()];
                requestTokenSecret = dict[ProtocolParameters.oauth_token_secret.ToString()];

                string authorizeUrlWithParameters = authorizeUrl + "?" + ProtocolParameters.oauth_token.ToString() + "=" + requestToken;
                WebBrowserTask ie = new WebBrowserTask();
                ie.URL = authorizeUrlWithParameters;
                ie.Show();
            }
        }

        private static string GetTimeSpan()
        {
            double seconds = (DateTime.Now - DateTime.Parse("1970/1/1")).TotalSeconds;
            seconds = seconds < 0 ? 0 : seconds;
            string timeSpan = string.Format("{0:0}", seconds);
            return timeSpan;
        }

        public static void GetAccessToken(string verifier)
        {
            string timeSpan = GetTimeSpan();
            Dictionary<ProtocolParameters, string> protocolParameters = new Dictionary<ProtocolParameters, string>();
            protocolParameters.Add(ProtocolParameters.oauth_consumer_key, appKey);
            protocolParameters.Add(ProtocolParameters.oauth_nonce, timeSpan);
            protocolParameters.Add(ProtocolParameters.oauth_signature_method, "HMAC-SHA1");
            protocolParameters.Add(ProtocolParameters.oauth_timestamp, timeSpan);
            protocolParameters.Add(ProtocolParameters.oauth_token, requestToken);
            protocolParameters.Add(ProtocolParameters.oauth_verifier, verifier);

            string signature = SignatureBaseString(HttpVerb.GET, accessTokenUrl, protocolParameters, null, appSecret, requestTokenSecret);

            protocolParameters.Add(ProtocolParameters.oauth_signature, signature);
            string authorizationString = GetAuthorizationString(protocolParameters);

            WebClient client = new WebClient();
            client.Headers["Authorization"] = authorizationString;
            client.OpenReadCompleted += new OpenReadCompletedEventHandler(CompleteAccessToken);
            client.OpenReadAsync(new Uri(accessTokenUrl));
        }

        private static void CompleteAccessToken(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                Stream reply = null;
                StreamReader reader = null;
                string content = string.Empty;

                try
                {
                    reply = (Stream)e.Result;
                    reader = new StreamReader(reply);
                    content = reader.ReadLine();
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }

                    if (reply != null)
                    {
                        reply.Close();
                    }
                }

                string[] tokens = content.Split('&');

                if (tokens.Length != 3)
                {
                    return;
                }

                Dictionary<string, string> dict = new Dictionary<string, string>();

                foreach (string item in tokens)
                {
                    string[] keyValue = item.Split('=');
                    dict.Add(keyValue[0], keyValue[1]);
                }

                accessToken = dict[ProtocolParameters.oauth_token.ToString()];
                accessTokenSecret = dict[ProtocolParameters.oauth_token_secret.ToString()];
                userId = dict["user_id"];
            }
        }

        private static string OAuthUrlEncode(string url)
        {
            char[] temp = HttpUtility.UrlEncode(url).Replace("+", "%20").ToCharArray();
            for (int i = 0; i < temp.Length - 2; i++)
            {
                if (temp[i] == '%')
                {
                    temp[i + 1] = char.ToUpper(temp[i + 1]);
                    temp[i + 2] = char.ToUpper(temp[i + 2]);
                }
            }
            return new string(temp);
        }

        public static void SendMessage(string message)
        {
            Dictionary<string, string> data = new Dictionary<string, string>();
            data.Add("status", message);
            CommonPostData("http://api.t.sina.com.cn/statuses/update.xml", data, CompleteSendMessage);
        }

        private static void CompleteSendMessage(object sender, UploadStringCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                string content = e.Result;
            }
        }

        public static void GetUserInfo()
        {
            CommonGetData("http://api.t.sina.com.cn/users/hot.xml", CompleteGetUserInfo);
        }

        private static void CompleteGetUserInfo(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                Stream reply = null;
                StreamReader reader = null;
                string content = string.Empty;

                try
                {
                    reply = (Stream)e.Result;
                    reader = new StreamReader(reply);
                    content = reader.ReadToEnd();
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }

                    if (reply != null)
                    {
                        reply.Close();
                    }
                }
            }
        }

        private static void CommonPostData(string targetUrl, Dictionary<string, string> postedData, UploadStringCompletedEventHandler callback)
        {
            string timeSpan = GetTimeSpan();
            Dictionary<ProtocolParameters, string> protocolParameters = new Dictionary<ProtocolParameters, string>();
            protocolParameters.Add(ProtocolParameters.oauth_consumer_key, appKey);
            protocolParameters.Add(ProtocolParameters.oauth_nonce, timeSpan);
            protocolParameters.Add(ProtocolParameters.oauth_signature_method, "HMAC-SHA1");
            protocolParameters.Add(ProtocolParameters.oauth_timestamp, timeSpan);
            protocolParameters.Add(ProtocolParameters.oauth_token, accessToken);

            string signature = SignatureBaseString(HttpVerb.POST, targetUrl, protocolParameters, postedData, appSecret, accessTokenSecret);

            protocolParameters.Add(ProtocolParameters.oauth_signature, signature);
            string authorizationString = GetAuthorizationString(protocolParameters);

            StringBuilder postedDataBuilder = new StringBuilder();
            if (postedData != null && postedData.Count > 0)
            {
                foreach (var parameter in postedData)
                {
                    postedDataBuilder.Append(OAuthUrlEncode(parameter.Key) + "=" + OAuthUrlEncode(parameter.Value));
                    postedDataBuilder.Append("&");
                }
            }
            string postedDataString = postedDataBuilder.ToString().TrimEnd('&');

            WebClient client = new WebClient();
            client.Headers["Authorization"] = authorizationString;
            client.Headers["Content-Type"] = "application/x-www-form-urlencoded";
            client.UploadStringCompleted += callback;
            client.UploadStringAsync(new Uri(targetUrl), postedDataString);
        }

        private static void CommonGetData(string targetUrl, OpenReadCompletedEventHandler callback)
        {
            string timeSpan = GetTimeSpan();
            Dictionary<ProtocolParameters, string> protocolParameters = new Dictionary<ProtocolParameters, string>();
            protocolParameters.Add(ProtocolParameters.oauth_consumer_key, appKey);
            protocolParameters.Add(ProtocolParameters.oauth_nonce, timeSpan);
            protocolParameters.Add(ProtocolParameters.oauth_signature_method, "HMAC-SHA1");
            protocolParameters.Add(ProtocolParameters.oauth_timestamp, timeSpan);
            protocolParameters.Add(ProtocolParameters.oauth_token, accessToken);

            string signature = SignatureBaseString(HttpVerb.GET, targetUrl, protocolParameters, null, appSecret, accessTokenSecret);

            protocolParameters.Add(ProtocolParameters.oauth_signature, signature);
            string authorizationString = GetAuthorizationString(protocolParameters);

            WebClient client = new WebClient();
            client.Headers["Authorization"] = authorizationString;
            client.OpenReadCompleted += callback;
            client.OpenReadAsync(new Uri(targetUrl));
        }
    }
}
